home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / machserver / tests / processTree / processTree.c < prev   
Encoding:
C/C++ Source or Header  |  1992-04-30  |  7.9 KB  |  383 lines

  1. /* 
  2.  * processTree.c --
  3.  *
  4.  *    Test program to do lots of forks and execs.  Basically the program 
  5.  *    spawns a small tree of processes, in which a process forks off some 
  6.  *    children, waits a random interval, then exits.
  7.  *    
  8.  *    Usage: processTree [ numSecs ]
  9.  *    
  10.  *    where "numSecs" is the minimum number of seconds to run.  (The 
  11.  *    default is to run forever.)  After numSecs seconds the top-level 
  12.  *    process stops creating new processes, and eventually the program 
  13.  *    exits. 
  14.  *
  15.  * Copyright 1991 Regents of the University of California
  16.  * Permission to use, copy, modify, and distribute this
  17.  * software and its documentation for any purpose and without
  18.  * fee is hereby granted, provided that this copyright
  19.  * notice appears in all copies.  The University of California
  20.  * makes no representations about the suitability of this
  21.  * software for any purpose.  It is provided "as is" without
  22.  * express or implied warranty.
  23.  */
  24.  
  25. #ifndef lint
  26. static char rcsid[] = "$Header: /user5/kupfer/spriteserver/tests/processTree/RCS/processTree.c,v 1.5 92/04/29 22:32:45 kupfer Exp $ SPRITE (Berkeley)";
  27. #endif /* not lint */
  28.  
  29. #include <errno.h>
  30. #include <sprite.h>
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <string.h>
  34. #include <sys/wait.h>
  35. #include <sys/time.h>
  36. #include <sys/types.h>
  37. #include <sys/resource.h>
  38. #include <test.h>
  39. #include <unistd.h>
  40.  
  41. #define USE_STDIO        /* use printf instead of Test_PutTime */
  42.  
  43. #define NUM_CHILDREN_1ST    2 /* number of immediate children to keep 
  44.                    * running */
  45. #define MAX_CHILDREN_2ND    10 /* maximum number of children to be 
  46.                     * created by a first-generation child */
  47. #define MAX_PRINTFS        5 /* maximum number of printfs for a 
  48.                    * process to do before exiting */
  49. #define MAX_SLEEP_TIME        20 /* maximum number of seconds to sleep 
  50.                     * between printf's */
  51.  
  52. extern int FromInterval();
  53.  
  54. /* Forward references: */
  55.  
  56. static void BeAChild();
  57. static int Lookup();
  58. static pid_t MakeChild();
  59. static void PrintfLoop();
  60. static void PrintTime();
  61. static void ReapChildren();
  62. static void SleepSome();
  63.  
  64.  
  65. /*
  66.  *----------------------------------------------------------------------
  67.  *
  68.  * main --
  69.  *
  70.  *    Run forever; start a new top-level child when one exits.
  71.  *
  72.  * Results:
  73.  *    None.
  74.  *
  75.  * Side effects:
  76.  *    None.
  77.  *
  78.  *----------------------------------------------------------------------
  79.  */
  80.  
  81. void
  82. main(argc, argv)
  83.     int argc;
  84.     char **argv;
  85. {
  86.     int child;
  87.     pid_t children[NUM_CHILDREN_1ST];
  88.     pid_t deadDescendant;
  89.     time_t stopTime = 0;    /* if non-zero, don't create new processes 
  90.                  * after this time */
  91.  
  92.     /* 
  93.      * Initialization.
  94.      */
  95.     for (child = 0; child < NUM_CHILDREN_1ST; ++child) {
  96.     children[child] = MakeChild(TRUE);
  97.     }
  98.     if (argc > 1) {
  99.     stopTime = time((time_t *)0) + atoi(argv[1]);
  100.     }
  101.  
  102.     /* 
  103.      * When a direct descendant dies, start a replacement, up until the
  104.      * stopping time (if any).  If we're running as the initial process, we
  105.      * inherit 2nd generation processes as well.  When those die, take no
  106.      * additional action.
  107.      */
  108.     
  109.     for (;;) {
  110.     deadDescendant = wait((union wait *)0);
  111.     if (deadDescendant < 0) {
  112.         if (stopTime == 0 || time((time_t *)0) < stopTime) {
  113.         perror("Wait at top level failed");
  114.         exit(1);
  115.         }
  116.         exit(0);
  117.     }
  118.     child = Lookup(deadDescendant, children);
  119.     if (child != -1) {
  120.         if (stopTime == 0 || time((time_t *)0) < stopTime) {
  121.         children[child] = MakeChild(TRUE);
  122.         }
  123.     }
  124.     }
  125. }
  126.  
  127.  
  128. /*
  129.  *----------------------------------------------------------------------
  130.  *
  131.  * MakeChild --
  132.  *
  133.  *    Make a child process.
  134.  *
  135.  * Results:
  136.  *    In the parent, returns the pid of the child.  In the child, never 
  137.  *    returns.
  138.  *
  139.  * Side effects:
  140.  *    None.
  141.  *
  142.  *----------------------------------------------------------------------
  143.  */
  144.  
  145. static pid_t
  146. MakeChild(moreChildren)
  147.     Boolean moreChildren;    /* should the child make addition children? */
  148. {
  149.     pid_t childPid;
  150.  
  151.     childPid = fork();
  152.     switch (childPid) {
  153.     case -1:
  154.     perror("Can't create child");
  155.     exit(1);
  156.     break;
  157.     case 0:
  158.     BeAChild(moreChildren);
  159.     exit(0);
  160.     break;
  161.     }
  162.  
  163.     return childPid;
  164. }
  165.  
  166.  
  167. /*
  168.  *----------------------------------------------------------------------
  169.  *
  170.  * BeAChild --
  171.  *
  172.  *    Create some number of child processes if asked to do so.  Then do a
  173.  *    random number of printfs, sleeping a random time between printfs
  174.  *    and checking for dead children.  Then return.
  175.  *
  176.  * Results:
  177.  *    None.
  178.  *
  179.  * Side effects:
  180.  *    None.
  181.  *
  182.  *----------------------------------------------------------------------
  183.  */
  184.  
  185. static void
  186. BeAChild(makeChildren)
  187.     Boolean makeChildren;
  188. {
  189.     int numChildren;
  190.     int child;
  191.  
  192.     /* 
  193.      * Reinitialize the random number generator, using our pid.  Otherwise, 
  194.      * all the processes run in lock step.
  195.      */
  196.     srandom(getpid());
  197.  
  198.     /* 
  199.      * Even though we're supposed to make children, we don't want any 
  200.      * grandchildren. 
  201.      */
  202.     if (makeChildren) {
  203.     numChildren = FromInterval(1, MAX_CHILDREN_2ND);
  204.     for (child = 0; child < numChildren; ++child) {
  205.         (void)MakeChild(FALSE);
  206.     }
  207.     }
  208.  
  209.     PrintfLoop(makeChildren);
  210. }
  211.  
  212.  
  213. /*
  214.  *----------------------------------------------------------------------
  215.  *
  216.  * PrintfLoop --
  217.  *
  218.  *    Do a random number of printfs over a random time interval.  Each 
  219.  *    time through the loop, reap any children that have died.
  220.  *
  221.  * Results:
  222.  *    None.
  223.  *
  224.  * Side effects:
  225.  *    None.
  226.  *
  227.  *----------------------------------------------------------------------
  228.  */
  229.  
  230. static void
  231. PrintfLoop(expectChildren)
  232.     Boolean expectChildren;    /* should there be children to reap? */
  233. {
  234.     int numMessages = FromInterval(1, MAX_PRINTFS);
  235.     int msg;            /* message (printf) number */
  236.  
  237.     for (msg = 0; msg < numMessages; ++msg) {
  238.     PrintTime();
  239.     SleepSome();
  240.     if (expectChildren) {
  241.         ReapChildren();
  242.     }
  243.     }
  244. }
  245.  
  246.  
  247. /*
  248.  *----------------------------------------------------------------------
  249.  *
  250.  * PrintTime --
  251.  *
  252.  *    Backspace over the previous time message and write the current 
  253.  *    time.
  254.  *
  255.  * Results:
  256.  *    None.
  257.  *
  258.  * Side effects:
  259.  *    None.
  260.  *
  261.  *----------------------------------------------------------------------
  262.  */
  263.  
  264. static void
  265. PrintTime()
  266. {
  267.     time_t now;
  268. #ifdef USE_STDIO
  269.     char buf[26];
  270. #endif
  271.  
  272.     now = time((time_t *)0);
  273. #ifdef USE_STDIO
  274.     strcpy(buf, ctime(&now));
  275.     buf[24] = '\0';
  276.     printf("\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b%s",
  277.        buf);
  278.     fflush(stdout);
  279. #else
  280.     Test_PutTime(now, TRUE);
  281. #endif
  282. }
  283.  
  284.  
  285. /*
  286.  *----------------------------------------------------------------------
  287.  *
  288.  * SleepSome --
  289.  *
  290.  *    Pick a random number of seconds and sleep for that long.
  291.  *
  292.  * Results:
  293.  *    None.
  294.  *
  295.  * Side effects:
  296.  *    None.
  297.  *
  298.  *----------------------------------------------------------------------
  299.  */
  300.  
  301. static void
  302. SleepSome()
  303. {
  304.     int numSecs;
  305.  
  306.     numSecs = FromInterval(1, MAX_SLEEP_TIME);
  307.     sleep(numSecs);
  308. }
  309.  
  310.  
  311. /*
  312.  *----------------------------------------------------------------------
  313.  *
  314.  * ReapChildren --
  315.  *
  316.  *    Reap any dead children.  If there aren't any currently, return.
  317.  *
  318.  * Results:
  319.  *    None.
  320.  *
  321.  * Side effects:
  322.  *    None.
  323.  *
  324.  *----------------------------------------------------------------------
  325.  */
  326.  
  327. static void
  328. ReapChildren()
  329. {
  330.     pid_t childPid;
  331.  
  332.     for (;;) {
  333.     childPid = wait3((union wait *)0, WNOHANG, (struct rusage *)0);
  334.     /* no children died */
  335.     if (childPid == 0) {
  336.         break;
  337.     }
  338.     /* all our children died before we did */
  339.     if (childPid < 0 && errno == ECHILD) {
  340.         break;
  341.     }
  342.     if (childPid < 0) {
  343.         perror("Wait for child failed");
  344.         exit(1);
  345.     }
  346.     }
  347. }
  348.  
  349.  
  350. /*
  351.  *----------------------------------------------------------------------
  352.  *
  353.  * Lookup --
  354.  *
  355.  *    Find the given child in the table of children.
  356.  *
  357.  * Results:
  358.  *    Returns the table index for the child, or -1 if the child isn't in 
  359.  *    the table.
  360.  *
  361.  * Side effects:
  362.  *    None.
  363.  *
  364.  *----------------------------------------------------------------------
  365.  */
  366.  
  367. static int
  368. Lookup(child, childTable)
  369.     pid_t child;
  370.     pid_t *childTable;        /* table with NUM_CHILDREN_1ST entries */
  371. {
  372.     int index;
  373.  
  374.     for (index = 0; index < NUM_CHILDREN_1ST; ++index) {
  375.     if (childTable[index] == child) {
  376.         return index;
  377.     }
  378.     }
  379.  
  380.     return -1;
  381. }
  382.  
  383.